# coding=UTF-8
# author=suemi
# created at 16/5/13
from utils import Constants
from elasticsearch import Elasticsearch
from elasticsearch import helpers
from utils.PageUtil import ArticleIterator
import traceback

def check(func):
    """
    检查索引是否存在,不存在则创建
    :return:
    """

    def handle_args(self, *args, **kwargs):  # 处理传入函数的参数
        if not self.conn.indices.exists(self.current[0]):
            tmp = self.meta[self.current]
            self.create(self.current[0], self.current[1], tmp[0], tmp[1])
        func(self, *args, **kwargs)

    return handle_args


class IndexManager:
    """ Summary Of This Class
    负责向ES提交修改和删除索引
    """

    def __init__(self, batchSize=500,
                 host=Constants.ES_SETTINGS['host'],
                 port=Constants.ES_SETTINGS['port']):
        self.batchSize = batchSize
        self.conn = Elasticsearch([host + ':' + str(port)])
        self.meta = {
            (Constants.INDEX_NAME, Constants.INDEX_TYPE): (Constants.INDEX_SETTINGS, Constants.INDEX_MAPPINGS)
        }
        self.current = (Constants.INDEX_NAME, Constants.INDEX_TYPE)

    def create(self, indexName=Constants.INDEX_NAME, indexType=Constants.INDEX_TYPE,
               settings=Constants.INDEX_SETTINGS, mappings=Constants.INDEX_MAPPINGS):
        """
        创建索引条目
        :return:
        """
        parameters = {
            'settings': settings,
            'mappings': {
                indexType: {
                    'properties':mappings
                }
            }
        }
        self.conn.indices.create(indexName, body=parameters)
        self.meta[(indexName, indexType)] = (settings, mappings)
        self.current = (indexName, indexType)
        return self

    def specify(self, indexName, indexType=None):
        """
        设定当前处理的索引名和类型
        :param indexName:
        :param indexType:
        :return:
        """
        self.current = (indexName, indexType)
        return self

    def batch(self, size):
        if size < 1:
            raise ValueError("Batch Size Must Be Greater Than 0!")
        self.batchSize = size
        return self

    @check
    def insert(self, article):
        """
        提交一篇文章给ES
        :param article:
        :return:
        """
        try:
            self.conn.index(self.current[0], self.current[1], article.toDict(), article.documentId())
        except Exception, e:
            traceback.print_exc()

    @check
    def refresh(self):
        try:
            self.conn.indices.refresh(self.current[0])
        except Exception, e:
            traceback.print_exc()

    @check
    def delete(self, article):
        """
        删除特定文章的索引
        :param article:
        :return:
        """
        try:
            self.conn.delete(self.current[0], self.current[1], article.documentId())
        except Exception, e:
            traceback.print_exc()

    @check
    def update(self, article, delta=None):
        if delta is None:
            delta = article.toDict()
        try:
            self.conn.update(self.current[0], self.current[1], article.documentId(), body=delta)
        except Exception, e:
            traceback.print_exc()

    @check
    def submit(self, articles):
        """
        批量提交索引
        :param articles:
        :return:
        """
        count = 0
        actions = []
        if isinstance(articles, list):
            articles = iter(articles)
        while True:
            if count == self.batchSize:
                helpers.bulk(self.conn, actions)
                self.refresh()
                count = 0
                actions = []
            try:
                article = articles.next()
                action = {
                    "_index": self.current[0],
                    "_type": self.current[1],
                    "_id": article.documentId(),
                    "_source": article.toDict()
                }
                actions.append(action)
                count += 1
            except StopIteration, e:
                break
            except Exception, e:
                traceback.print_exc()
                continue
        helpers.bulk(self.conn, actions)
        self.refresh()

    def destroy(self):
        """
        删除所有索引
        :return:
        """
        try:
            self.conn.indices.delete(self.current[0])
        except Exception, e:
            traceback.print_exc()
